home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 11 / develop 11 code / Async Sound Helper / Sound Helper Demo / SHDemo.c < prev    next >
Encoding:
Text File  |  1992-07-15  |  12.1 KB  |  448 lines  |  [TEXT/MPS ]

  1. //=======================================================================================
  2. //
  3. // SHDemo.c - an application to demonstrate the use of the Asynchronous Sound Helper
  4. //
  5. // Written by Bryan K. Ressler (Beaker), 2/4/92
  6. //
  7. // Version 1.00, 2/4/92        Original version
  8. //         1.10, 4/11/92    Integrate final Sound Helper, clean up
  9. //
  10. //=======================================================================================
  11.  
  12. //=======================================================================================
  13. // Includes
  14. //=======================================================================================
  15. #include "Std.h"
  16. #include "SHDemo.h"
  17. #include "SoundHelper.h"
  18.  
  19. //=======================================================================================
  20. // Globals
  21. //=======================================================================================
  22. Boolean            gHelperNeedsTime;            // Flags that Sound Helper needs an Idle call
  23.  
  24. Boolean            gSoundIn = false;            // Whether we can record
  25. short            gRecorderState;                // Record/playback state
  26.  
  27. Boolean            gBeatOn = false;            // Beat sound on/off
  28. long            gBeatRefNum;                // Beat sound's reference number
  29. SndChannelPtr    gBeatChannel;                // The beat sound channel
  30.  
  31. long            gProgressCurrent;            // Progress bar's current value
  32. long            gProgressMin;                // Progress bar's minimum value
  33. long            gProgressMax;                // Progress bar's maximum value
  34.  
  35. Handle            gUserSnd = nil;                // Handle to user's recording (nil if none)
  36. long            gUserSndRef;                // Reference number of user's recording
  37. short            gRecLevel;                    // Current recording level
  38. Boolean            gRecDone;                    // Tells whether recording has completed
  39.  
  40. DialogPtr        gSHDialog;                    // Sound Helper dialog
  41.  
  42. //=======================================================================================
  43. // Static prototypes
  44. //=======================================================================================
  45. static Boolean Init(SysEnvRec *env);
  46. static pascal void BoxItem(WindowPtr theWindow, short itemNum);
  47. static pascal void LevelItem(WindowPtr theWindow,short itemNum);
  48. static pascal void ProgressItem(WindowPtr theWindow,short itemNum);
  49. static void ProgressSetup(long min, long max, long value);
  50. static void Progress(DialogPtr dialog, short itemNum, long value, Boolean redraw);
  51. static Boolean SoundSetup(void);
  52. static void SetRecorderState(short newState);
  53. static Boolean DialogSetup(void);
  54. static void DialogIdle(void);
  55. static Boolean DialogHit(short item);
  56. static void SHDemo(void);
  57.  
  58. //=======================================================================================
  59. Boolean Init(SysEnvRec *env)
  60. {
  61.     short    err;
  62.     long    response, inRefNum;
  63.     
  64.     // The usual Mac initialization stuff
  65.     InitGraf(&qd.thePort);
  66.     InitFonts();
  67.     InitWindows();
  68.     TEInit();
  69.     InitDialogs(nil);
  70.     InitCursor();
  71.     
  72.     MaxApplZone();
  73.     
  74.     err = SysEnvirons(2,env);
  75.     if (!err && env->systemVersion >= kMinSystem) {
  76.         if (Gestalt(gestaltSoundAttr, &response) == noErr &&
  77.                 (response >> gestaltSoundIOMgrPresent) & 0x01) {
  78.             if (SPBOpenDevice(nil, siWritePermission, &inRefNum) == noErr) {
  79.                 SPBCloseDevice(inRefNum);
  80.                 gSoundIn = true;
  81.             }
  82.         }
  83.         return(true);
  84.     } else return(false);
  85. }
  86.  
  87. //=======================================================================================
  88. pascal void BoxItem(WindowPtr theWindow, short itemNum)
  89. {
  90.     short    aType;
  91.     Rect    theBox;
  92.     Handle    aHandle;
  93.  
  94.     GetDItem(theWindow, itemNum, &aType, &aHandle, &theBox);
  95.     PenNormal(); ForeColor(blackColor);
  96.     FrameRect(&theBox);
  97. }
  98.  
  99. //=======================================================================================
  100. pascal void LevelItem(WindowPtr theWindow,short itemNum)
  101. {
  102.     short    aType,endOfBox,totalBar;
  103.     Rect    theBox;
  104.     Handle    aHandle;
  105.  
  106.     GetDItem(theWindow,itemNum,&aType,&aHandle,&theBox);
  107.     PenNormal(); ForeColor(blackColor);
  108.     FrameRect(&theBox);
  109.     InsetRect(&theBox,1,1);
  110.     endOfBox = theBox.right;
  111.     totalBar = theBox.right - theBox.left;
  112.     theBox.right = theBox.left + ((gRecLevel * totalBar) / kNumRecLevelSteps);
  113.     PenPat(&qd.dkGray); PaintRect(&theBox);
  114.     theBox.left = theBox.right; theBox.right = endOfBox;
  115.     EraseRect(&theBox);
  116.     PenNormal();
  117. }
  118.  
  119. //=======================================================================================
  120. pascal void ProgressItem(WindowPtr theWindow,short itemNum)
  121. {
  122.     short    aType,endOfBox,totalBar;
  123.     long    totalRange,normalValue;
  124.     Rect    theBox;
  125.     Handle    aHandle;
  126.  
  127.     GetDItem(theWindow,itemNum,&aType,&aHandle,&theBox);
  128.     PenNormal(); ForeColor(blackColor);
  129.     FrameRect(&theBox);
  130.     InsetRect(&theBox,1,1);
  131.     if (gProgressMin == 0 && gProgressMax == 0) {
  132.         EraseRect(&theBox);
  133.     } else {
  134.         endOfBox = theBox.right;
  135.         normalValue = gProgressCurrent - gProgressMin;
  136.         totalRange = gProgressMax - gProgressMin;
  137.         totalBar = theBox.right - theBox.left;
  138.         theBox.right = theBox.left + ((normalValue * totalBar) / totalRange);
  139.         PenPat(&qd.dkGray); PaintRect(&theBox);
  140.         theBox.left = theBox.right; theBox.right = endOfBox;
  141.         EraseRect(&theBox);
  142.     }
  143.     PenNormal();
  144. }
  145.  
  146. //=======================================================================================
  147. void ProgressSetup(long min, long max, long value)
  148. {
  149.     gProgressMin = min;
  150.     gProgressMax = max;
  151.     gProgressCurrent = value;
  152. }
  153.  
  154. //=======================================================================================
  155. void Progress(DialogPtr dialog, short itemNum, long value, Boolean redraw)
  156. {
  157.     gProgressCurrent = value;
  158.     if (redraw)
  159.         ProgressItem(dialog, itemNum);
  160. }
  161.  
  162. //=======================================================================================
  163. Boolean SoundSetup(void)
  164. {
  165.     short    err;
  166.     Handle    snd;
  167.  
  168.     // Get a sound channel from the Helper by calling SHPlayByHandle with a nil handle.
  169.     err = SHPlayByHandle(nil,&gBeatRefNum);
  170.     if (err)
  171.         return(false);
  172.     else {
  173.         err = SHGetChannel(gBeatRefNum,&gBeatChannel);
  174.         if (err)
  175.             return(false);
  176.         
  177.         snd = GetResource(soundListRsrc,kDanceBeat);
  178.         if (snd) {
  179.             err = SndPlay(gBeatChannel,snd,true);        // FIX ME
  180.             return(err ? false : true);
  181.         } else return(false);
  182.     }
  183. }
  184.  
  185. //=======================================================================================
  186. void SetRecorderState(short newState)
  187. {
  188.     Boolean    rec, play, stop, pause;
  189.     char    blank = 0;
  190.     Str255    parm0;
  191.     
  192.     switch (newState) {
  193.         case kIdleNoSound:
  194.             rec = gSoundIn;
  195.             play = stop = pause = false;
  196.             break;
  197.         case kIdleSound:
  198.             rec = gSoundIn;
  199.             play = true;
  200.             stop = pause = false;
  201.             break;
  202.         case kRecording:
  203.         case kRecordPaused:
  204.         case kPlaying:
  205.         case kPlayPaused:
  206.             stop = pause = true;
  207.             rec = play = false;
  208.             break;
  209.     }
  210.     
  211.     if (rec)
  212.         EnCtrl(gSHDialog, kRecordBtn);
  213.     else DisCtrl(gSHDialog, kRecordBtn);
  214.     if (play)
  215.         EnCtrl(gSHDialog, kPlayBtn);
  216.     else DisCtrl(gSHDialog, kPlayBtn);
  217.     if (stop)
  218.         EnCtrl(gSHDialog, kStopBtn);
  219.     else DisCtrl(gSHDialog, kStopBtn);
  220.     if (pause)
  221.         EnCtrl(gSHDialog, kPauseBtn);
  222.     else DisCtrl(gSHDialog, kPauseBtn);
  223.     
  224.     GetIndString(parm0, kStrs, kFirstStateStr + newState);
  225.     ParamText(parm0, &blank, &blank, &blank);
  226.     InvalItem(gSHDialog, kRecPlayStatus);
  227.     
  228.     if (newState != kRecording) {
  229.         gRecLevel = 0;
  230.         LevelItem(gSHDialog, kLevelBar);
  231.     }
  232.  
  233.     gRecorderState = newState;
  234. }
  235.  
  236. //=======================================================================================
  237. Boolean DialogSetup(void)
  238. {
  239.     short    item;
  240.     
  241.     gSHDialog = GetNewDialog(kSHDialog, nil, (WindowPtr)-1);
  242.     if (gSHDialog == nil)
  243.         return(false);
  244.  
  245.     // Set up dialog items
  246.     SetPort(gSHDialog);
  247.     for (item = 0; item < kNumBoxItems; item++)
  248.         UserItem(gSHDialog, kFirstBoxItem + item, BoxItem);
  249.     UserItem(gSHDialog, kProgressBar, ProgressItem);
  250.     ProgressSetup(0, 0, 0);
  251.     UserItem(gSHDialog, kLevelBar, LevelItem);
  252.     SetRecorderState(kIdleNoSound);
  253.     ShowWindow(gSHDialog);
  254. }
  255.  
  256. //=======================================================================================
  257. void DialogIdle(void)
  258. {
  259.     SHRecordStatusRec    recStat;
  260.     SHPlayStat            playStatus;
  261.  
  262.     // Update the level meter if recording
  263.     SetPort(gSHDialog);
  264.     if (gRecorderState == kRecording) {
  265.         SetPort(gSHDialog);
  266.         SHRecordStatus(&recStat);
  267.         Progress(gSHDialog, kProgressBar, recStat.currentRecordTime, true);
  268.         gRecLevel = recStat.meterLevel;
  269.         LevelItem(gSHDialog, kLevelBar);
  270.     }
  271.  
  272.     // Notice when recording has stopped
  273.     if ((gRecorderState == kRecording || gRecorderState == kRecordPaused) && gRecDone) {
  274.         SetRecorderState(kIdleSound);
  275.         SHGetRecordedSound(&gUserSnd);
  276.         ProgressSetup(0, 0, 0);
  277.         Progress(gSHDialog, kProgressBar, 0, true);
  278.     }
  279.     
  280.     // Notice when playback has stopped
  281.     playStatus = SHPlayStatus(gUserSndRef);
  282.     if ((gRecorderState == kPlaying || gRecorderState == kPlayPaused) &&
  283.             (playStatus == shpFinished || playStatus == shpError))
  284.         SetRecorderState(kIdleSound);
  285. }
  286.  
  287. //=======================================================================================
  288. Boolean DialogHit(short item)
  289. {
  290.     Boolean                done = false;
  291.     short                sndID,err;
  292.     SndCommand            cmd;
  293.     SHRecordStatusRec    recStat;
  294.     
  295.     // Handle dialog items
  296.     SetPort(gSHDialog);
  297.     switch (item) {
  298.         case kQuit:
  299.             done = true;
  300.             break;
  301.         case kAbout :
  302.             Alert(kAboutAlert, nil);
  303.             break;
  304.         case kFillBtn:
  305.         case kHitBtn:
  306.             sndID = (item == kFillBtn) ? kFillSnd : kHitSnd;
  307.             err = SHPlayByID(sndID, nil);
  308.             if (err == kSHErrOutaChannels)
  309.                 StopAlert(kOutaChannelsAlert, nil);
  310.             else if (err)
  311.                 ErrorExtra(kPlayError, err);
  312.             break;
  313.         case kBeatCheck:
  314.             gBeatOn = !gBeatOn;
  315.             SetValue(gSHDialog, kBeatCheck, gBeatOn);
  316.             cmd.param1 = 0;
  317.             if (gBeatOn) {
  318.                 cmd.cmd = freqCmd;
  319.                 cmd.param2 = kMiddleC;
  320.             } else {
  321.                 cmd.cmd = quietCmd;
  322.                 cmd.param2 = 0;
  323.             }
  324.             SndDoImmediate(gBeatChannel,&cmd);    // ignore error
  325.             break;
  326.         case kRecordBtn:
  327.             if (gRecorderState == kIdleSound || gRecorderState == kIdleNoSound) {
  328.                 if (gRecorderState == kIdleSound && gUserSnd != nil) {
  329.                     DisposHandle(gUserSnd);
  330.                     gUserSnd = nil;
  331.                 }
  332.                 err = SHRecordStart(kMaxUserRecording, 'best', &gRecDone);
  333.                 if (err)
  334.                     ErrorExtra(kRecordError, err);
  335.                 else {
  336.                     SetRecorderState(kRecording);
  337.                     SHRecordStatus(&recStat);
  338.                     ProgressSetup(0, recStat.totalRecordTime,
  339.                         recStat.currentRecordTime);
  340.                 }
  341.             } else SysBeep(10);
  342.             break;
  343.         case kPlayBtn:
  344.             if (gRecorderState == kIdleSound && gUserSnd != nil) {
  345.                 err = SHPlayByHandle(gUserSnd, &gUserSndRef);
  346.                 if (err == noErr)
  347.                     SetRecorderState(kPlaying);
  348.                 else if (err == kSHErrOutaChannels)
  349.                     StopAlert(kOutaChannelsAlert, nil);
  350.                 else if (err)
  351.                     ErrorExtra(kPlayError, err);
  352.             } else SysBeep(10);
  353.             break;
  354.         case kStopBtn:
  355.             if (gRecorderState == kPlaying || gRecorderState == kPlayPaused)
  356.                 SHPlayStop(gUserSndRef);
  357.             else if (gRecorderState == kRecording || gRecorderState == kRecordPaused)
  358.                 SHRecordStop();
  359.             else SysBeep(10);
  360.             break;
  361.         case kPauseBtn:
  362.             switch (gRecorderState) {
  363.                 case kRecording:
  364.                     SHRecordPause();
  365.                     SetRecorderState(kRecordPaused);
  366.                     break;
  367.                 case kRecordPaused:
  368.                     SHRecordContinue();
  369.                     SetRecorderState(kRecording);
  370.                     break;
  371.                 case kPlaying:
  372.                     SHPlayPause(gUserSndRef);
  373.                     SetRecorderState(kPlayPaused);
  374.                     break;
  375.                 case kPlayPaused:
  376.                     SHPlayContinue(gUserSndRef);
  377.                     SetRecorderState(kPlaying);
  378.                     break;
  379.                 default:
  380.                     SysBeep(10);
  381.                     break;
  382.             }
  383.             break;
  384.     }
  385.     
  386.     return(done);
  387. }
  388.  
  389. //=======================================================================================
  390. void SHDemo(void)
  391. {
  392.     GrafPtr        oldPort;
  393.     DialogPtr    dlg;
  394.     short        itemHit;
  395.     EventRecord    event;
  396.     Boolean        done = false;
  397.         
  398.     // Initialize Helper
  399.     if (SHInitSoundHelper(&gHelperNeedsTime, kMaxChannels) != noErr) {
  400.         ErrorAlert(kCantInitSH);
  401.         return;
  402.     }
  403.     
  404.     // Set up the beat box sound channel
  405.     if (!SoundSetup()) {
  406.         ErrorAlert(kCantGetChannel);
  407.         SHKillSoundHelper();
  408.         return;
  409.     }
  410.     
  411.     // Save port and set up the main dialog
  412.     GetPort(&oldPort);
  413.     if (!DialogSetup())
  414.         return;
  415.     
  416.     // Our little event loop
  417.     do {
  418.         // Give the Sound Helper an SHIdle call if it needs one
  419.         if (gHelperNeedsTime)
  420.             SHIdle();
  421.         
  422.         // Update the level meter if recording
  423.         DialogIdle();
  424.         
  425.         // Get events and handle the dialog
  426.         WaitNextEvent(everyEvent, &event, 0, nil);
  427.         if (IsDialogEvent(&event) && DialogSelect(&event, &dlg, &itemHit))
  428.             done = DialogHit(itemHit);
  429.     } while (!done);
  430.     
  431.     // Lose the dialog
  432.     DisposeDialog(gSHDialog);
  433.     SetPort(oldPort);
  434.     
  435.     // Kill the Helper
  436.     SHKillSoundHelper();
  437. }
  438.  
  439. //=======================================================================================
  440. main()
  441. {
  442.     SysEnvRec    env;
  443.  
  444.     if (Init(&env))
  445.         SHDemo();                            // Knock yourself out!
  446.     else ErrorAlert(kBadEnv);
  447. }
  448.